package com.mdd.front.service.course.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper;
import com.mdd.common.config.GlobalConfig;
import com.mdd.common.core.PageResult;
import com.mdd.common.entity.course.*;
import com.mdd.common.entity.system.Coupon;
import com.mdd.common.entity.teacher.Teacher;
import com.mdd.common.entity.user.User;
import com.mdd.common.mapper.course.*;
import com.mdd.common.mapper.system.CouponMapper;
import com.mdd.common.mapper.teacher.TeacherMapper;
import com.mdd.common.mapper.user.UserMapper;
import com.mdd.common.utils.LsConfigUtil;
import com.mdd.common.utils.StringUtil;
import com.mdd.common.utils.TimeUtil;
import com.mdd.common.utils.UrlUtil;
import com.mdd.front.LikeFrontInterceptor;
import com.mdd.front.LikeFrontThreadLocal;
import com.mdd.front.service.course.ICourseService;
import com.mdd.front.utils.SearchUtils;
import com.mdd.front.validate.CourseStudyParam;
import com.mdd.front.validate.PageParam;
import com.mdd.front.validate.StudyCourseCatalogueParam;
import com.mdd.front.validate.StudyCourseCatalogueScheduleParam;
import com.mdd.front.vo.course.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.util.*;

/**
 * 课程实现类
 */
@Service
public class CourseServiceImpl implements ICourseService {
        
    @Resource
    CourseMapper courseMapper;

    @Resource
    CourseImageMapper courseImageMapper;

    @Resource
    TeacherMapper teacherMapper;

    @Resource
    CourseCatalogueMapper courseCatalogueMapper;

    @Resource
    StudyCourseMapper studyCourseMapper;

    @Resource
    StudyCourseCatalogueMapper studyCourseCatalogueMapper;

    @Resource
    CourseCollectMapper courseCollectMapper;

    @Resource
    UserMapper userMapper;

    @Resource
    CourseCommentImageMapper courseCommentImageMapper;

    @Resource
    CourseMaterialMapper courseMaterialMapper;

    @Resource
    CouponMapper couponMapper;



    /**
     * 课程列表
     *
     * @param pageParam 分页参数
     * @param params 搜索参数
     * @return PageResult<LsCourseListVo>
     */
    @Override
    public PageResult<CourseListVo> list(PageParam pageParam, Map<String, String> params) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("COUNT(catalogue.id) as catalogueCount")
//                .select("teacher.name as teacherName, category.name as category, COUNT(catalogue.id) as catalogueCount")
                .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
//                .innerJoin("?_teacher teacher ON teacher.id=t.teacher_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.status", "1")
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));

        if (StringUtil.isNotEmpty(params.get("keyword"))) {
            String keyword = params.get("keyword");
            Integer userId = LikeFrontThreadLocal.getUserId();

            SearchUtils.addHot(keyword);
            SearchUtils.addSearchHistoryByUserId(userId, keyword);

            mpjQueryWrapper.nested(wq->wq
                    .like("t.name", keyword).or()
                    .like("category.name", keyword).or());
        }

        IPage<CourseListVo> iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseListVo.class, mpjQueryWrapper);

        for(CourseListVo item : iPage.getRecords()) {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        }

        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }

    /**
     * 我的收藏课程列表
     *
     * @param pageParam 分页参数
     * @return PageResult<LsCourseListVo>
     */
    @Override
    public PageResult<CourseListVo> favorites(PageParam pageParam) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        Integer userId = LikeFrontThreadLocal.getUserId();
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("COUNT(catalogue.id) as catalogueCount")
                .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course_collect collect ON collect.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.status", "1")
                .eq("collect.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));

        IPage<CourseListVo> iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseListVo.class, mpjQueryWrapper);

        for(CourseListVo item : iPage.getRecords()) {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        }

        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }

    @Override
    public Map<String, Object> getMyComments(Integer userId) {
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("comment.id AS commentId, comment.course_score AS courseScore, comment.comment AS comment, comment.reply AS reply, comment.update_time AS commentUpdateTime, o.id AS orderId ")
                .innerJoin("?_order_course oc ON oc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON oc.order_id = o.id AND o.order_status = 2 AND o.delete_time IS NULL".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin(("?_course_comment comment ON t.id = comment.course_id AND comment.user_id = " + userId).replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("o.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("o.update_time"));
        List<CourseMineCommentVo> courses = courseMapper.selectJoinList(CourseMineCommentVo.class, mpjQueryWrapper);
        Map<String, Object> resultMap = new HashMap<>();
        List<CourseMineCommentVo> noComments = new LinkedList<>();
        List<CourseMineCommentVo> commented = new LinkedList<>();
        courses.forEach(item -> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
            item.setCommentUpdateTime(TimeUtil.timestampToDate(item.getCommentUpdateTime()));
            if (item.getCourseScore() != null) {
                QueryWrapper<CourseCommentImage> commentImgQueryWrapper = new QueryWrapper<>();
                commentImgQueryWrapper.eq("comment_id", item.getCommentId());
                List<CourseCommentImage> commentImageList = courseCommentImageMapper.selectList(commentImgQueryWrapper);
                List<String> commentImages = new LinkedList<>();
                commentImageList.forEach(imageItem -> {
                    commentImages.add(UrlUtil.toAbsoluteUrl(imageItem.getUri()));
                });
                item.setCommentImages(commentImages);
                commented.add(item);
            } else {
                noComments.add(item);
            }
        });
        resultMap.put("noComments", noComments);
        resultMap.put("noCommentsCount", Integer.valueOf(noComments.size()));
        resultMap.put("commented", commented);
        resultMap.put("commentedCount", Integer.valueOf(commented.size()));
        return resultMap;
    }

    @Override
    public PageResult<CourseMineCommentVo> getMyCommentList(PageParam pageParam, Integer userId, int type) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("comment.id AS commentId, comment.course_score AS courseScore, comment.comment AS comment, comment.reply AS reply, comment.update_time AS commentUpdateTime, o.id AS orderId ")
                .innerJoin("?_order_course oc ON oc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON oc.order_id = o.id AND o.order_status = 2 AND o.delete_time IS NULL".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin(("?_course_comment comment ON t.id = comment.course_id AND comment.user_id = " + userId).replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("o.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("o.update_time"));

        if (type == 1) {
            mpjQueryWrapper.isNotNull("comment.id");
        } else {
            mpjQueryWrapper.isNull("comment.id");
        }

        IPage<CourseMineCommentVo> iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseMineCommentVo.class, mpjQueryWrapper);
        iPage.getRecords().forEach(item -> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
            if (type == 1) {
                item.setCommentUpdateTime(TimeUtil.timestampToDate(item.getCommentUpdateTime()));
                QueryWrapper<CourseCommentImage> commentImgQueryWrapper = new QueryWrapper<>();
                commentImgQueryWrapper.eq("comment_id", item.getCommentId());
                List<CourseCommentImage> commentImageList = courseCommentImageMapper.selectList(commentImgQueryWrapper);
                List<String> commentImages = new LinkedList<>();
                commentImageList.forEach(imageItem -> {
                    commentImages.add(UrlUtil.toAbsoluteUrl(imageItem.getUri()));
                });
                item.setCommentImages(commentImages);
            }
        });
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }

    @Override
    public PageResult<CourseMineCommentVo> getMyCommented(PageParam pageParam, Integer userId) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("comment.id AS commentId, comment.course_score AS courseScore, comment.comment AS comment, comment.reply AS reply, comment.update_time AS commentUpdateTime, o.id AS orderId ")
                .innerJoin("?_order_course oc ON oc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON oc.order_id = o.id AND o.order_status = 2 AND o.delete_time IS NULL".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin(("?_course_comment comment ON t.id = comment.course_id AND comment.user_id = " + userId).replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .isNotNull("comment.id")
                .eq("o.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("o.update_time"));
        IPage<CourseMineCommentVo> iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseMineCommentVo.class, mpjQueryWrapper);
        List<CourseMineCommentVo> commented = new LinkedList<>();
        iPage.getRecords().forEach(item -> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
            item.setCommentUpdateTime(TimeUtil.timestampToDate(item.getCommentUpdateTime()));
            QueryWrapper<CourseCommentImage> commentImgQueryWrapper = new QueryWrapper<>();
            commentImgQueryWrapper.eq("comment_id", item.getCommentId());
            List<CourseCommentImage> commentImageList = courseCommentImageMapper.selectList(commentImgQueryWrapper);
            List<String> commentImages = new LinkedList<>();
            commentImageList.forEach(imageItem -> {
                commentImages.add(UrlUtil.toAbsoluteUrl(imageItem.getUri()));
            });
            item.setCommentImages(commentImages);
            commented.add(item);
        });
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), commented);
    }

    @Override
    public PageResult<CourseMineCommentVo> getMyNoComment(PageParam pageParam, Integer userId) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("comment.id AS commentId, comment.course_score AS courseScore, comment.comment AS comment, comment.reply AS reply, comment.update_time AS commentUpdateTime, o.id AS orderId ")
                .innerJoin("?_order_course oc ON oc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON oc.order_id = o.id AND o.order_status = 2 AND o.delete_time IS NULL".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin(("?_course_comment comment ON t.id = comment.course_id AND comment.user_id = " + userId).replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .isNull("comment.id")
                .eq("o.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("o.update_time"));
        IPage<CourseMineCommentVo> iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseMineCommentVo.class, mpjQueryWrapper);
        iPage.getRecords().forEach(item -> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        });
        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }

    @Override
    public Map<String, Object> getMyCommentCount(Integer userId) {
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("comment.id AS commentId, comment.course_score AS courseScore, comment.comment AS comment, comment.reply AS reply, comment.update_time AS commentUpdateTime, o.id AS orderId ")
                .innerJoin("?_order_course oc ON oc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_order o ON oc.order_id = o.id AND o.order_status = 2 AND o.delete_time IS NULL".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin(("?_course_comment comment ON t.id = comment.course_id AND comment.user_id = " + userId).replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("o.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("o.update_time"));
        List<CourseMineCommentVo> courses = courseMapper.selectJoinList(CourseMineCommentVo.class, mpjQueryWrapper);
        Map<String, Object> resultMap = new HashMap<>();
        List<CourseMineCommentVo> noComments = new LinkedList<>();
        List<CourseMineCommentVo> commented = new LinkedList<>();
        courses.forEach(item -> {
            if (item.getCourseScore() != null) {
                commented.add(item);
            } else {
                noComments.add(item);
            }
        });
        resultMap.put("noCommentsCount", Integer.valueOf(noComments.size()));
        resultMap.put("commentedCount", Integer.valueOf(commented.size()));
        return resultMap;
    }

    @Override
    public Map<String, List<CourseMineVo>> listMine(Integer userId) {

        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
        percent.setMaximumFractionDigits(3); //百分比小数点最多3位
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("SUM(CASE WHEN catalogue.id IS NOT NULL THEN 1 ELSE 0 END) as catalogueCount, IFNULL(sc.status, 1) AS learnState")
                .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id ".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_study_course sc ON sc.course_id = t.id AND sc.delete_time IS NULL ".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("sc.user_id", userId)
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("sc.update_time"));

        List<CourseMineVo> courses = courseMapper.selectJoinList(CourseMineVo.class, mpjQueryWrapper);

        Map<String, List<CourseMineVo>> resultMap = new HashMap<>();
        List<CourseMineVo> free = new LinkedList<>();
        List<CourseMineVo> fee = new LinkedList<>();
        courses.forEach(item -> {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
            int type = item.getType() != null ? item.getType() : 0;
            //先过滤专栏数据
            if (type == 1 || type == 2 || type == 3) {
                int feeType = item.getFeeType() != null ? item.getFeeType() : 0;

                //还需要获取最后一次学习的课程目录
                MPJQueryWrapper<CourseCatalogue> courseCatalogueQueryWrapper = new MPJQueryWrapper<CourseCatalogue>()
                        .selectAll(CourseCatalogue.class)
                        .innerJoin("?_study_course_catalogue scc ON scc.catalogue_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                        .eq("t.status", "1")
                        .eq("scc.user_id", userId)
                        .eq("scc.course_id", item.getId())
                        .orderByDesc(Arrays.asList("scc.update_time", "scc.create_time"));
                List<CourseCatalogue> courseCatalogues = courseCatalogueMapper.selectJoinList(CourseCatalogue.class, courseCatalogueQueryWrapper);

                if (courseCatalogues == null || courseCatalogues.size() == 0) {
                    courseCatalogues = courseCatalogueMapper.selectList(new QueryWrapper<CourseCatalogue>()
                            .eq("course_id", item.getId())
                            .eq("status", "1").orderByAsc(Arrays.asList("sort", "id")));
                }

                item.setStudyCatalogues(courseCatalogues);
                BigDecimal catalogueCount = new BigDecimal(String.valueOf(item.getCatalogueCount()));
                BigDecimal studyCatalogueCount = new BigDecimal(String.valueOf(courseCatalogues.size()));

                if (studyCatalogueCount.doubleValue() != 0 && catalogueCount.doubleValue() != 0) {
                    BigDecimal studyRate = studyCatalogueCount.divide(catalogueCount, 2, BigDecimal.ROUND_DOWN);
                    item.setStudyRate(percent.format(studyRate));
                } else {
                    item.setStudyRate(percent.format(new BigDecimal("0")));
                }

                //还需要计算课程的学习进度

                if (feeType == 1) {
                    fee.add(item);
                } else {
                    free.add(item);
                }
            }

        });
        resultMap.put("fee", fee);
        resultMap.put("free", free);
        return resultMap;
    }

    /**
     * 热门课程
     *
     * @param topN 获取的个数
     * @return List<CourseListVo>
     */
    public List<CourseListVo> listHotTopN(Integer topN) {
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("teacher.name as teacherName, category.name as category, COUNT(catalogue.id) as catalogueCount, t.study_num + t.virtual_study_num AS totalStudyNum")
                .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_teacher teacher ON teacher.id=t.teacher_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.status", "1")
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("totalStudyNum", "t.update_time"))
                .last("limit " + topN);
        List<CourseListVo> courseListVos = courseMapper.selectJoinList(CourseListVo.class, mpjQueryWrapper);
        for(CourseListVo item : courseListVos) {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        }
        return courseListVos;
    }

    /**
     * 精选课程
     *
     * @return List<CourseListVo>
     */
    public List<CourseListVo> listChosen() {
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("teacher.name as teacherName, category.name as category, COUNT(catalogue.id) as catalogueCount")
                .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_teacher teacher ON teacher.id=t.teacher_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("t.status", "1")
                .eq("t.is_choice", "1")
                .groupBy("t.id")
                .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));
        List<CourseListVo> courseListVos = courseMapper.selectJoinList(CourseListVo.class, mpjQueryWrapper);
        for(CourseListVo item : courseListVos) {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        }
        return courseListVos;
    }

    /**
     * 课程详情
     *
     * @param id 主键参数
     * @return CourseDetailVo
     */
    @Override
    public CourseDetailVo detail(Integer id, Integer userId) {
        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
        percent.setMaximumFractionDigits(3); //百分比小数点最多3位
        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                    .eq("id", id)
                    .last("limit 1"));
        Assert.notNull(model, "数据不存在");

        CourseDetailVo vo = new CourseDetailVo();
        BeanUtils.copyProperties(model, vo);
        vo.setCover(UrlUtil.toAbsoluteUrl(vo.getCover()));
        List<CourseImage> courseImages = courseImageMapper.selectList(new QueryWrapper<CourseImage>().eq("course_id", id));
        List<CourseImageDetailVo> courseImageDetailVos = new ArrayList<>();
        courseImages.forEach(item -> {
            CourseImageDetailVo courseImageDetailVo = new CourseImageDetailVo();
            BeanUtils.copyProperties(item, courseImageDetailVo);
            courseImageDetailVo.setAbsoluteUrl(UrlUtil.toAbsoluteUrl(courseImageDetailVo.getUri()));
            courseImageDetailVos.add(courseImageDetailVo);
        });
        vo.setImages(courseImageDetailVos);
        //获取讲师信息
        Integer teacherId = model.getTeacherId();
        Teacher teacher = teacherMapper.selectOne(
                new QueryWrapper<Teacher>()
                        .eq("id", teacherId)
                        .last("limit 1"));
        if (teacher != null) {
            teacher.setAvatar(UrlUtil.toAbsoluteUrl(teacher.getAvatar()));
            vo.setTeacher(teacher);
        }

        int type = model.getType() != null ? model.getType() : 0;

        List<CourseCatalogue> courseCatalogues = courseCatalogueMapper.selectList(new QueryWrapper<CourseCatalogue>()
                .eq("course_id", model.getId())
                .eq("status", "1").orderByAsc(Arrays.asList("sort", "id")));

        List<CourseCatalogueDetailVo> vos = new ArrayList<>();
        courseCatalogues.forEach(item -> {
            CourseCatalogueDetailVo courseCatalogueDetailVo = new CourseCatalogueDetailVo();
            BeanUtils.copyProperties(item, courseCatalogueDetailVo);
            courseCatalogueDetailVo.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));

            StudyCourseCatalogue studyCourseCatalogue = studyCourseCatalogueMapper.selectOne(
                    new QueryWrapper<StudyCourseCatalogue>()
                            .eq("course_id", id)
                            .eq("user_id", userId)
                            .eq("catalogue_id", item.getId())
                            .last("limit 1"));

            if (studyCourseCatalogue != null) {
                courseCatalogueDetailVo.setStudyStatus(studyCourseCatalogue.getStatus());
            }

            if (type == 2 || type == 3) {
                courseCatalogueDetailVo.setContent(UrlUtil.toAbsoluteUrl(item.getContent()));
                courseCatalogueDetailVo.setDurationStr(timeToStr(item.getDuration()));
                if (studyCourseCatalogue != null) {
                    Long studyCatalogueDuration = studyCourseCatalogue.getDuration() != null ? studyCourseCatalogue.getDuration() : 0l;
                    courseCatalogueDetailVo.setStudyDuration(studyCatalogueDuration);
                    Long itemDuration = item.getDuration() != null ? item.getDuration() : 0l;
                    if (itemDuration.longValue() == 0 || studyCatalogueDuration.longValue() == 0) {
                        courseCatalogueDetailVo.setStudyRate(percent.format(new BigDecimal("0")));
                    }  else {
                        BigDecimal studyRate = new BigDecimal(String.valueOf(studyCatalogueDuration)).divide(new BigDecimal(itemDuration), 3, RoundingMode.HALF_UP);
                        courseCatalogueDetailVo.setStudyRate(percent.format(studyRate));
                    }
                } else {
                    courseCatalogueDetailVo.setStudyRate(percent.format(new BigDecimal("0")));
                }
            }
//            StudyCourseCatalogue studyCourseCatalogue = studyCourseCatalogueMapper.selectOne(new QueryWrapper<StudyCourseCatalogue>().eq("user_id", userId).eq("catalogue_id", item.getId()).eq("course_id", item.getCourseId()).last("limit 1"));
//            courseCatalogueDetailVo.setLearned(studyCourseCatalogue != null);
            vos.add(courseCatalogueDetailVo);
        });

        vo.setCourseCatalogues(vos);
        if (userId != null) {
            StudyCourse studyCourse = studyCourseMapper.selectOne(
                    new QueryWrapper<StudyCourse>()
                            .eq("course_id", model.getId())
                            .eq("user_id", userId)
                            .isNull("delete_time")
                            .last("limit 1"));
            vo.setPurchased(studyCourse != null);
            vo.setLearnState(studyCourse != null ? studyCourse.getStatus() : 1);

            CourseCollect courseCollect = courseCollectMapper.selectOne(
                    new QueryWrapper<CourseCollect>()
                            .eq("course_id", model.getId())
                            .eq("user_id", userId)
                            .last("limit 1"));
            vo.setCollected(courseCollect != null);
        } else {
            vo.setPurchased(false);
            vo.setCollected(false);
        }

        vo.setBtn_str(LsConfigUtil.get("transaction", "btn_str", "购买课程"));
        vo.setAllowPurchase(Integer.parseInt(LsConfigUtil.get("transaction", "purchase", "1")));
        return vo;
    }

    private String timeToStr(Long time) {
        time = time != null ? time : 0l;
        time = time / 1000;
        long hour = time / 3600;
        long min = time / 60 % 60;
        long second = time % 60;
        String hourString;
        String minString;
        String secondString;
        hourString = hour + "";

        if (min < 10) {
            minString = "0" + min;
        } else {
            minString = min + "";
        }

        if (second < 10) {
            secondString = "0" + second;
        } else {
            secondString = second + "";
        }

        return hourString + ":" + minString + ":" + secondString;
    }

    @Override
    public CourseCatalogueDetailVo getCourseCatalogueDetail(Integer id, Integer userId) {
        NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
        percent.setMaximumFractionDigits(3); //百分比小数点最多3位
        CourseCatalogue courseCatalogue = this.courseCatalogueMapper.selectById(id);
        Assert.notNull(courseCatalogue, "课程目录数据不存在");
        Integer courseId = courseCatalogue.getCourseId();
        Course course = this.courseMapper.selectById(courseId);
        //如果是收费课程需要判断当前用户是否已经购买当前课程
        if (course.getFeeType().intValue() == 1 && courseCatalogue.getFeeType().intValue() == 1) {
            StudyCourse studyCourse = studyCourseMapper.selectOne(new QueryWrapper<StudyCourse>().eq("user_id", userId).eq("course_id", courseId).isNull("delete_time").last("limit 1"));
            Assert.notNull(studyCourse, "请付费后观看");
        }
        Assert.notNull(course, "课程数据不存在");
        int type = course.getType();
        CourseCatalogueDetailVo courseCatalogueDetailVo = new CourseCatalogueDetailVo();
        BeanUtils.copyProperties(courseCatalogue, courseCatalogueDetailVo);
        courseCatalogueDetailVo.setCover(UrlUtil.toAbsoluteUrl(courseCatalogue.getCover()));
        StudyCourseCatalogue studyCourseCatalogue = studyCourseCatalogueMapper.selectOne(
                new QueryWrapper<StudyCourseCatalogue>()
                        .eq("course_id", courseCatalogue.getCourseId())
                        .eq("user_id", userId)
                        .eq("catalogue_id", courseCatalogue.getId())
                        .last("limit 1"));
        if (studyCourseCatalogue != null) {
            courseCatalogueDetailVo.setStudyStatus(studyCourseCatalogue.getStatus());
        }
        if (type == 2 || type == 3) {
            courseCatalogueDetailVo.setContent(UrlUtil.toAbsoluteUrl(courseCatalogue.getContent()));
            courseCatalogueDetailVo.setDurationStr(timeToStr(courseCatalogue.getDuration()));
            if (studyCourseCatalogue != null) {
                Long studyCatalogueDuration = studyCourseCatalogue.getDuration() != null ? studyCourseCatalogue.getDuration() : 0l;
                courseCatalogueDetailVo.setStudyDuration(studyCatalogueDuration);
                Long itemDuration = courseCatalogue.getDuration() != null ? courseCatalogue.getDuration() : 0l;
                if (itemDuration.longValue() == 0 || studyCatalogueDuration.longValue() == 0) {
                    courseCatalogueDetailVo.setStudyRate(percent.format(new BigDecimal("0")));
                }  else {
                    BigDecimal studyRate = new BigDecimal(String.valueOf(studyCatalogueDuration)).divide(new BigDecimal(itemDuration), 3, RoundingMode.HALF_UP);
                    courseCatalogueDetailVo.setStudyRate(percent.format(studyRate));
                }
            } else {
                courseCatalogueDetailVo.setStudyRate(percent.format(new BigDecimal("0")));
            }
        }
        return courseCatalogueDetailVo;
    }

    /**
     * 课程资料详情
     *
     * @param courseId 课程id
     * @return CourseMaterialDetailVo
     */
    public  CourseMaterialDetailVo getMaterialDetail(Integer courseId) {
        CourseMaterial model = courseMaterialMapper.selectOne(
                new QueryWrapper<CourseMaterial>()
                        .eq("course_id", courseId)
                        .last("limit 1"));
        if(model != null) {
            CourseMaterialDetailVo vo = new CourseMaterialDetailVo();
            BeanUtils.copyProperties(model, vo);
//            vo.setContent(UrlUtil.toAbsoluteUrl(vo.getContent()));
            return vo;
        }
        return null;
    }

    @Override
    public List<CourseColumnListVo> listColumns(PageParam pageParam, Map<String, String> params, Integer courseId) {
        MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                .selectAll(Course.class)
                .select("teacher.name as teacherName, category.name as category, c.id as columnId, c.fee_type as columnFeeType ")
                .innerJoin("?_course_column c ON t.id = c.relation_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin("?_teacher teacher ON teacher.id=t.teacher_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .leftJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                .eq("c.course_id", courseId)
                .orderByDesc(Arrays.asList("t.sort", "t.id"));
        courseMapper.setSearch(mpjQueryWrapper, params, new String[]{
                "like:name@t.name:str",
                "=:type@t.type:int",
        });
        List<CourseColumnListVo> result = courseMapper.selectJoinList(CourseColumnListVo.class, mpjQueryWrapper);
        for(CourseColumnListVo item : result) {
            item.setCreateTime(TimeUtil.timestampToDate(item.getCreateTime()));
            item.setUpdateTime(TimeUtil.timestampToDate(item.getUpdateTime()));
        }
        return result;
    }

    @Override
    public boolean collect(Integer id, Integer userId) {

        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                        .eq("id", id)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(model, "课程数据不存在");


        CourseCollect courseCollect = courseCollectMapper.selectOne(
                new QueryWrapper<CourseCollect>()
                        .eq("course_id", id)
                        .eq("user_id", userId)
                        .last("limit 1"));

        if(courseCollect != null) {
            return courseCollectMapper.deleteById(courseCollect.getId()) > 0;
        } else {
            courseCollect = new CourseCollect();
            courseCollect.setCourseId(id);
            courseCollect.setUserId(userId);
            courseCollect.setCreateTime(TimeUtil.timestamp());
            return courseCollectMapper.insert(courseCollect) > 0;
        }

    }

    @Override
    public boolean addCourseStudy(Integer courseId, Integer userId, Integer sourceId) {
        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                        .eq("id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(model, "课程数据不存在");
        Assert.isTrue(model.getFeeType() != null && model.getFeeType().intValue() != 1, "当前课程为收费课程，不可直接加入");
        User user = userMapper.selectOne(
                new QueryWrapper<User>()
                        .eq("id", userId)
                        .last("limit 1"));
        Assert.notNull(user, "用户不存在");

        StudyCourse studyCourse = studyCourseMapper.selectOne(
                new QueryWrapper<StudyCourse>()
                        .eq("course_id", courseId)
                        .eq("user_id", userId)
                        .last("limit 1"));
        Assert.isNull(studyCourse, "已加入当前课程，无需重复加入");
        studyCourse = new StudyCourse();
        studyCourse.setCourseId(courseId);
        studyCourse.setUserId(userId);
        studyCourse.setSourceId(sourceId);
        studyCourse.setStatus(1);
        studyCourse.setCreateTime(TimeUtil.timestamp());
        studyCourse.setUpdateTime(TimeUtil.timestamp());
        this.studyCourseMapper.insert(studyCourse);
        Integer studyNum = model.getStudyNum() != null ? model.getStudyNum() + 1 : 1;
        model.setStudyNum(studyNum);
        return this.courseMapper.updateById(model) > 0;
    }

    @Override
    public boolean studyCourse(Integer courseId, Integer userId) {
        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                        .eq("id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(model, "课程数据不存在");

        User user = userMapper.selectOne(
                new QueryWrapper<User>()
                        .eq("id", userId)
                        .last("limit 1"));
        Assert.notNull(user, "用户不存在");

        StudyCourse studyCourse = studyCourseMapper.selectOne(
                new QueryWrapper<StudyCourse>()
                        .eq("course_id", courseId)
                        .eq("user_id", userId)
                        .last("limit 1"));

        Assert.notNull(studyCourse, "当前用户未加入课程");
        studyCourse.setStatus(2);
        studyCourse.setUpdateTime(TimeUtil.timestamp());
        return this.studyCourseMapper.updateById(studyCourse) > 0;
    }

    @Override
    public PageResult<CourseListVo> listByCoupon(PageParam pageParam, Integer couponId, String courseName) {
        Integer page  = pageParam.getPageNo();
        Integer limit = pageParam.getPageSize();

        Coupon coupon = this.couponMapper.selectById(couponId);
        Assert.notNull(coupon, "优惠券不存在");

        IPage<CourseListVo> iPage = null;
        if (coupon.getUsed().intValue() == 2) {
            MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                    .selectAll(Course.class)
                    .select("COUNT(catalogue.id) as catalogueCount")
                    .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .innerJoin("?_coupon_course cc ON cc.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .eq("cc.coupon_id", couponId)
                    .eq("t.status", "1")
                    .groupBy("t.id")
                    .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));
            if (StringUtil.isNotEmpty(courseName)) {
                mpjQueryWrapper.eq("t.name", courseName);
            }
            iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseListVo.class, mpjQueryWrapper);
        } else if (coupon.getUsed().intValue() == 3) {

            List<Integer> couponIds = this.courseMapper.getCourseIdByCouponId(couponId);

            MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                    .selectAll(Course.class)
                    .select("COUNT(catalogue.id) as catalogueCount")
                    .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .eq("t.status", "1")
                    .notIn("t.id", couponIds)
                    .groupBy("t.id")
                    .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));
            if (StringUtil.isNotEmpty(courseName)) {
                mpjQueryWrapper.eq("t.name", courseName);
            }
            iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseListVo.class, mpjQueryWrapper);

        } else {
            MPJQueryWrapper<Course> mpjQueryWrapper = new MPJQueryWrapper<Course>()
                    .selectAll(Course.class)
                    .select("COUNT(catalogue.id) as catalogueCount")
                    .leftJoin("?_course_catalogue catalogue ON catalogue.course_id = t.id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .innerJoin("?_course_category category ON category.id=t.category_id".replace("?_", GlobalConfig.knowledgePaymentTablePrefixe))
                    .eq("t.status", "1")
                    .groupBy("t.id")
                    .orderByDesc(Arrays.asList("t.study_num", "t.update_time"));

            if (StringUtil.isNotEmpty(courseName)) {
                mpjQueryWrapper.eq("t.name", courseName);
            }
            iPage = courseMapper.selectJoinPage(new Page<>(page, limit), CourseListVo.class, mpjQueryWrapper);
        }

        for(CourseListVo item : iPage.getRecords()) {
            item.setCover(UrlUtil.toAbsoluteUrl(item.getCover()));
        }

        return PageResult.iPageHandle(iPage.getTotal(), iPage.getCurrent(), iPage.getSize(), iPage.getRecords());
    }

    @Override
    public boolean updateCatalogueSchedule(StudyCourseCatalogueScheduleParam studyCourseCatalogueScheduleParam) {
        Integer courseId = studyCourseCatalogueScheduleParam.getCourseId();
        Integer catalogueId = studyCourseCatalogueScheduleParam.getCatalogueId();
        Integer userId = studyCourseCatalogueScheduleParam.getUserId();

        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                        .eq("id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(model, "课程数据不存在");

        CourseCatalogue courseCatalogue = courseCatalogueMapper.selectOne(
                new QueryWrapper<CourseCatalogue>()
                        .eq("id", catalogueId)
                        .eq("course_id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(courseCatalogue, "课程不存在此课程目录");

        User user = userMapper.selectOne(
                new QueryWrapper<User>()
                        .eq("id", userId)
                        .last("limit 1"));
        Assert.notNull(user, "用户不存在");

//        if (model.getFeeType().intValue() == 1 && courseCatalogue.getFeeType().intValue() == 1) {
//            StudyCourse studyCourse = studyCourseMapper.selectOne(new QueryWrapper<StudyCourse>().eq("user_id", userId).eq("course_id", courseId).isNull("delete_time").last("limit 1"));
//            Assert.notNull(studyCourse, "请付费");
//        }

        StudyCourseCatalogue studyCourseCatalogue = studyCourseCatalogueMapper.selectOne(
                new QueryWrapper<StudyCourseCatalogue>()
                        .eq("course_id", courseId)
                        .eq("user_id", userId)
                        .eq("catalogue_id", catalogueId)
                        .last("limit 1"));

        if (studyCourseCatalogue == null) {
            studyCourseCatalogue = new StudyCourseCatalogue();
            studyCourseCatalogue.setCourseId(courseId);
            studyCourseCatalogue.setCatalogueId(catalogueId);
            studyCourseCatalogue.setUserId(userId);
            studyCourseCatalogue.setDuration(studyCourseCatalogueScheduleParam.getDuration());
            studyCourseCatalogue.setStatus(2);
            studyCourseCatalogue.setCreateTime(TimeUtil.timestamp());
            studyCourseCatalogue.setUpdateTime(TimeUtil.timestamp());
            return this.studyCourseCatalogueMapper.insert(studyCourseCatalogue) > 0;
        }
        studyCourseCatalogue.setStatus(2);
        studyCourseCatalogue.setDuration(studyCourseCatalogueScheduleParam.getDuration());
        studyCourseCatalogue.setCreateTime(TimeUtil.timestamp());
        studyCourseCatalogue.setUpdateTime(TimeUtil.timestamp());
        return this.studyCourseCatalogueMapper.updateById(studyCourseCatalogue) > 0;
    }

    @Override
    public boolean completeCourseCatalogue(StudyCourseCatalogueParam studyCourseCatalogueParam) {
        Integer courseId = studyCourseCatalogueParam.getCourseId();
        Integer catalogueId = studyCourseCatalogueParam.getCatalogueId();
        Integer userId = studyCourseCatalogueParam.getUserId();
        Course model = courseMapper.selectOne(
                new QueryWrapper<Course>()
                        .eq("id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(model, "课程数据不存在");

        CourseCatalogue courseCatalogue = courseCatalogueMapper.selectOne(
                new QueryWrapper<CourseCatalogue>()
                        .eq("id", catalogueId)
                        .eq("course_id", courseId)
                        .eq("status", "1")
                        .last("limit 1"));
        Assert.notNull(courseCatalogue, "课程不存在此课程目录");

        User user = userMapper.selectOne(
                new QueryWrapper<User>()
                        .eq("id", userId)
                        .last("limit 1"));
        Assert.notNull(user, "用户不存在");

        if (model.getFeeType().intValue() == 1 && courseCatalogue.getFeeType().intValue() == 1) {
            StudyCourse studyCourse = studyCourseMapper.selectOne(new QueryWrapper<StudyCourse>().eq("user_id", userId).eq("course_id", courseId).isNull("delete_time").last("limit 1"));
            Assert.notNull(studyCourse, "请付费");
        }

        StudyCourseCatalogue studyCourseCatalogue = studyCourseCatalogueMapper.selectOne(
                new QueryWrapper<StudyCourseCatalogue>()
                        .eq("course_id", courseId)
                        .eq("user_id", userId)
                        .eq("catalogue_id", catalogueId)
                        .last("limit 1"));

        if (studyCourseCatalogue == null) {
            studyCourseCatalogue = new StudyCourseCatalogue();
            studyCourseCatalogue.setCourseId(courseId);
            studyCourseCatalogue.setCatalogueId(catalogueId);
            studyCourseCatalogue.setUserId(userId);
            studyCourseCatalogue.setDuration(courseCatalogue.getDuration());
            studyCourseCatalogue.setStatus(3);
            studyCourseCatalogue.setCreateTime(TimeUtil.timestamp());
            studyCourseCatalogue.setUpdateTime(TimeUtil.timestamp());
            return this.studyCourseCatalogueMapper.insert(studyCourseCatalogue) > 0;
        } else {
            studyCourseCatalogue.setStatus(3);
            studyCourseCatalogue.setUpdateTime(TimeUtil.timestamp());
            return this.studyCourseCatalogueMapper.updateById(studyCourseCatalogue) > 0;
        }
    }
}
